package utils

import "sync"

/*
**
推荐使用GSyncMap
*/
type SyncKVMap struct {
	lock sync.RWMutex
	lst  []*KVRec
}

func NewSyncKVMap(capacity int) *SyncKVMap {
	rval := &SyncKVMap{
		lst: make([]*KVRec, 0, capacity),
	}
	return rval
}

func (this *SyncKVMap) Capacity() int {
	this.lock.RLock()
	defer this.lock.RUnlock()
	return cap(this.lst)
}

func (this *SyncKVMap) Count() int {
	this.lock.RLock()
	defer this.lock.RUnlock()
	return len(this.lst)
}

func (this *SyncKVMap) innerFindIdx(key interface{}) int {
	for i := 0; i < len(this.lst); i++ {
		if this.lst[i].Key == key {
			return i
		}
	}
	return -1
}

func (this *SyncKVMap) Find(key interface{}) *KVRec {
	this.lock.RLock()
	defer this.lock.RUnlock()
	idx := this.innerFindIdx(key)
	if idx == -1 {
		return nil
	}
	return this.lst[idx]
}

func (this *SyncKVMap) Set(key, val interface{}) {
	this.lock.Lock()
	defer this.lock.Unlock()
	idx := this.innerFindIdx(key)
	if idx == -1 {
		rec := &KVRec{key, val}
		this.lst = append(this.lst, rec)
	} else {
		this.lst[idx].Val = val
	}
}

func (this *SyncKVMap) RemoveEx(key interface{}) interface{} {
	this.lock.Lock()
	defer this.lock.Unlock()
	i := this.innerFindIdx(key)
	if i == -1 {
		return nil
	} else {
		rec := this.lst[i]
		lst := this.lst
		this.lst = append(lst[:i], lst[i+1:]...)
		return rec.Val
	}
}

func (this *SyncKVMap) Remove(key interface{}) bool {
	this.lock.Lock()
	defer this.lock.Unlock()
	i := this.innerFindIdx(key)
	if i == -1 {
		return false
	} else {
		lst := this.lst
		this.lst = append(lst[:i], lst[i+1:]...)
		return true
	}
}

/*
**

	注意:
	 	请勿在回调中进行Remove操作, 会造成死锁
*/
func (this *SyncKVMap) Range(cb func(key, val interface{}) bool) {
	this.lock.RLock()
	defer this.lock.RUnlock()
	for i := 0; i < len(this.lst); i++ {
		rec := this.lst[i]
		if !cb(rec.Key, rec.Val) {
			break
		}
	}
}

func (this *SyncKVMap) Get(key interface{}, def interface{}) interface{} {
	this.lock.RLock()
	defer this.lock.RUnlock()
	idx := this.innerFindIdx(key)
	if idx == -1 {
		return def
	}
	return this.lst[idx].Val
}
